home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1993 July / InfoMagic USENET CD-ROM July 1993.ISO / sources / misc / volume29 / zsh2.2 / part06 < prev    next >
Encoding:
Text File  |  1992-05-13  |  49.2 KB  |  2,235 lines

  1. Newsgroups: comp.sources.misc
  2. From: pfalstad@phoenix.Princeton.EDU (Paul Falstad)
  3. Subject:  v29i102:  zsh2.2 - The Z shell, Part06/17
  4. Message-ID: <1992May13.155947.8965@sparky.imd.sterling.com>
  5. X-Md4-Signature: 2b7f2af87640d2a32a75f021876c83aa
  6. Date: Wed, 13 May 1992 15:59:47 GMT
  7. Approved: kent@sparky.imd.sterling.com
  8.  
  9. Submitted-by: pfalstad@phoenix.Princeton.EDU (Paul Falstad)
  10. Posting-number: Volume 29, Issue 102
  11. Archive-name: zsh2.2/part06
  12. Environment: BSD
  13. Supersedes: zsh2.1: Volume 24, Issue 1-19
  14.  
  15. #!/bin/sh
  16. # this is aa.06 (part 6 of zsh2.2)
  17. # do not concatenate these parts, unpack them in order with /bin/sh
  18. # file zsh2.2/src/builtin.c continued
  19. #
  20. if test ! -r _shar_seq_.tmp; then
  21.     echo 'Please unpack part 1 first!'
  22.     exit 1
  23. fi
  24. (read Scheck
  25.  if test "$Scheck" != 6; then
  26.     echo Please unpack part "$Scheck" next!
  27.     exit 1
  28.  else
  29.     exit 0
  30.  fi
  31. ) < _shar_seq_.tmp || exit 1
  32. if test ! -f _shar_wnt_.tmp; then
  33.     echo 'x - still skipping zsh2.2/src/builtin.c'
  34. else
  35. echo 'x - continuing file zsh2.2/src/builtin.c'
  36. sed 's/^X//' << 'SHAR_EOF' >> 'zsh2.2/src/builtin.c' &&
  37. X *
  38. X * builtin.c - builtin commands
  39. X *
  40. X * This file is part of zsh, the Z shell.
  41. X *
  42. X * This software is Copyright 1992 by Paul Falstad
  43. X *
  44. X * Permission is hereby granted to copy, reproduce, redistribute or otherwise
  45. X * use this software as long as: there is no monetary profit gained
  46. X * specifically from the use or reproduction of this software, it is not
  47. X * sold, rented, traded or otherwise marketed, and this copyright notice is
  48. X * included prominently in any copy made. 
  49. X *
  50. X * The author make no claims as to the fitness or correctness of this software
  51. X * for any use whatsoever, and it is provided as is. Any use of this software
  52. X * is at the user's own risk. 
  53. X *
  54. X */
  55. X
  56. X#include "zsh.h"
  57. X#include <sys/errno.h>
  58. X
  59. X#define makecond() allocnode(N_COND)
  60. X
  61. X/* builtin flags */
  62. X
  63. X#define BINF_PLUSOPTS        1        /* +xyz legal */
  64. X#define BINF_R                    2        /* this is r (fc -e -) */
  65. X#define BINF_PRINTOPTS        4
  66. X#define BINF_SETOPTS            8
  67. X#define BINF_FCOPTS          16
  68. X#define BINF_TYPEOPT      32
  69. X#define BINF_TYPEOPTS      (BINF_TYPEOPT|BINF_PLUSOPTS)
  70. X#define BINF_ECHOPTS      64
  71. X
  72. X/* builtin funcs */
  73. X
  74. X#define BIN_TYPESET 0
  75. X#define BIN_BG 1
  76. X#define BIN_FG 2
  77. X#define BIN_JOBS 3
  78. X#define BIN_WAIT 4
  79. X#define BIN_DISOWN 5
  80. X#define BIN_BREAK 6
  81. X#define BIN_CONTINUE 7
  82. X#define BIN_EXIT 8
  83. X#define BIN_RETURN 9
  84. X#define BIN_SHIFT 10
  85. X#define BIN_CD 11
  86. X#define BIN_POPD 12
  87. X#define BIN_PUSHD 13
  88. X#define BIN_PRINT 14
  89. X#define BIN_EVAL 15
  90. X#define BIN_SCHED 16
  91. X#define BIN_FC 17
  92. X#define BIN_PUSHLINE 18
  93. X#define BIN_LOGOUT 19
  94. X#define BIN_BUILTIN 20
  95. X#define BIN_TEST 21
  96. X#define BIN_BRACKET 22
  97. X
  98. Xstruct bincmd {
  99. X    char *name;
  100. X    int (*handlerfunc) DCLPROTO((char *,char **,char *,int));
  101. X    int minargs;        /* min # of args */
  102. X    int maxargs;        /* max # of args, or -1 for no limit */
  103. X    int flags;            /* BINF_flags (see above) */
  104. X    int funcid;            /* xbins (see above) for overloaded handlerfuncs */
  105. X    char *optstr;        /* string of legal options */
  106. X    char *defopts;        /* options set by default for overloaded handlerfuncs */
  107. X    };
  108. X
  109. X/* structure for foo=bar assignments */
  110. X
  111. Xstruct asgment {
  112. X    struct asgment *next;
  113. X    char *name,*value;
  114. X    };
  115. X
  116. Xstatic char *auxdata;
  117. Xstatic int auxlen;
  118. Xstatic int showflag = 0,showflag2 = 0;
  119. X
  120. Xstruct bincmd builtins[] = {
  121. X    "[",bin_test,0,-1,0,BIN_BRACKET,NULL,NULL,
  122. X    ".",bin_dot,1,-1,0,0,NULL,NULL,
  123. X    ":",bin_colon,0,-1,0,0,NULL,NULL,
  124. X    "alias",bin_alias,0,-1,0,0,"ga",NULL,
  125. X    "autoload",bin_typeset,0,-1,BINF_TYPEOPTS,0,"tx","fu",
  126. X    "bg",bin_fg,0,-1,0,BIN_BG,NULL,NULL,
  127. X    "bindkey",bin_bindkey,0,-1,0,0,"asvemdrl",NULL,
  128. X    "break",bin_break,0,1,0,BIN_BREAK,NULL,NULL,
  129. X    "builtin",NULL,0,0,0,BIN_BUILTIN,NULL,NULL,
  130. X    "bye",bin_break,0,1,0,BIN_EXIT,NULL,NULL,
  131. X    "cd",bin_cd,0,2,0,BIN_CD,NULL,NULL,
  132. X    "chdir",bin_cd,0,2,0,BIN_CD,NULL,NULL,
  133. X    "compctl",bin_compctl,0,-1,0,0,NULL,NULL,
  134. X    "continue",bin_break,0,1,0,BIN_CONTINUE,NULL,NULL,
  135. X    "declare",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfilrtux",NULL,
  136. X    "dirs",bin_dirs,0,-1,0,0,"v",NULL,
  137. X    "disable",bin_disable,1,-1,0,0,NULL,NULL,
  138. X    "disown",bin_fg,1,-1,0,BIN_DISOWN,NULL,NULL,
  139. X    "echo",bin_print,0,-1,BINF_PRINTOPTS|BINF_ECHOPTS,BIN_PRINT,"n","-",
  140. X    "echotc",bin_echotc,1,-1,0,0,NULL,NULL,
  141. X    "enable",bin_enable,1,-1,0,0,NULL,NULL,
  142. X    "eval",bin_eval,0,-1,0,BIN_EVAL,NULL,NULL,
  143. X    "exit",bin_break,0,1,0,BIN_EXIT,NULL,NULL,
  144. X    "export",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfilrtu","x",
  145. X    "false",bin_let,0,0,0,0,NULL,NULL,
  146. X    "fc",bin_fc,0,-1,BINF_FCOPTS,BIN_FC,"nlreRWAdD",NULL,
  147. X    "fg",bin_fg,0,-1,0,BIN_FG,NULL,NULL,
  148. X    "functions",bin_typeset,0,-1,BINF_TYPEOPTS,0,"tu","f",
  149. X    "getln",bin_read,0,-1,0,0,NULL,"zr",
  150. X    "getopts",bin_getopts,2,-1,0,0,NULL,NULL,
  151. X    "hash",bin_hash,2,2,0,0,"r",NULL,
  152. X    "history",bin_fc,0,-1,0,BIN_FC,"nrdD","l",
  153. X    "integer",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZlrtux","i",
  154. X    "jobs",bin_fg,0,-1,0,BIN_JOBS,"lpZ",NULL,
  155. X    "kill",bin_kill,0,-1,0,0,NULL,NULL,
  156. X    "let",bin_let,1,-1,0,0,NULL,NULL,
  157. X    "limit",bin_limit,0,-1,0,0,"sh",NULL,
  158. X    "local",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfilrtux",NULL,
  159. X    "log",bin_log,0,0,0,0,NULL,NULL,
  160. X    "logout",bin_break,0,1,0,BIN_LOGOUT,NULL,NULL,
  161. X    "popd",bin_cd,0,2,0,BIN_POPD,NULL,NULL,
  162. X    "print",bin_print,0,-1,BINF_PRINTOPTS,BIN_PRINT,"RDPnrslzNu0123456789p-",NULL,
  163. X    "pushd",bin_cd,0,2,0,BIN_PUSHD,NULL,NULL,
  164. X    "pushln",bin_print,0,-1,BINF_PRINTOPTS,BIN_PRINT,NULL,"-nz",
  165. X    "pwd",bin_pwd,0,0,0,0,NULL,NULL,
  166. X    "r",bin_fc,0,-1,BINF_R,BIN_FC,"nrl",NULL,
  167. X    "read",bin_read,0,-1,0,0,"rzu0123456789p",NULL,
  168. X    "readonly",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfiltux","r",
  169. X    "rehash",bin_rehash,0,0,0,0,"f",NULL,
  170. X    "return",bin_break,0,1,0,BIN_RETURN,NULL,NULL,
  171. X    "sched",bin_sched,0,-1,0,0,NULL,NULL,
  172. X    "set",bin_set,0,-1,BINF_SETOPTS|BINF_PLUSOPTS,0,"0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZaefghijklnosuvwxy",NULL,
  173. X    "setopt",bin_setopt,0,-1,BINF_PLUSOPTS,0,"0123456789BCDEFGHIJKLMNOPQRSTUVWXYZaefghijklmnosuvwxy",NULL,
  174. X    "shift",bin_break,0,1,0,BIN_SHIFT,NULL,NULL,
  175. X    "source",bin_dot,1,-1,0,0,NULL,NULL,
  176. X    "suspend",bin_suspend,0,0,0,0,"f",NULL,
  177. X    "test",bin_test,0,-1,0,BIN_TEST,NULL,NULL,
  178. X    "ttyctl",bin_ttyctl,0,0,0,0,"fu",NULL,
  179. X    "times",bin_times,0,0,0,0,NULL,NULL,
  180. X    "trap",bin_trap,0,-1,0,0,NULL,NULL,
  181. X    "true",bin_colon,0,0,0,0,NULL,NULL,
  182. X    "type",bin_whence,0,-1,0,0,"pfa","v",
  183. X    "typeset",bin_typeset,0,-1,BINF_TYPEOPTS,0,"LRZfilrtux",NULL,
  184. X    "ulimit",bin_ulimit,0,1,0,0,"HSacdfmnt",NULL,
  185. X    "umask",bin_umask,0,1,0,0,NULL,NULL,
  186. X    "unalias",bin_unalias,1,-1,0,0,NULL,NULL,
  187. X    "unfunction",bin_unhash,1,-1,0,0,NULL,NULL,
  188. X    "unhash",bin_unhash,1,-1,0,0,NULL,NULL,
  189. X    "unlimit",bin_unlimit,0,-1,0,0,"h",NULL,
  190. X    "unset",bin_unset,1,-1,0,0,NULL,NULL,
  191. X    "unsetopt",bin_setopt,0,-1,BINF_PLUSOPTS,1,"0123456789BCDEFGHIJKLMNOPQRSTUWXYZabefghijklmnosuvwxy",NULL,
  192. X    "vared",bin_vared,1,1,0,0,NULL,NULL,
  193. X    "wait",bin_fg,0,-1,0,BIN_WAIT,NULL,NULL,
  194. X    "whence",bin_whence,0,-1,0,0,"pvcfa",NULL,
  195. X    "which",bin_whence,0,-1,0,0,"pa","c",
  196. X    NULL,NULL,0,0,0,0,NULL,NULL
  197. X    };
  198. X
  199. X/* print options */
  200. X
  201. Xstatic void prtopt()
  202. X{
  203. Xstruct option *opp;
  204. X
  205. X    if (isset(KSHOPTIONPRINT)) {
  206. X        printf("Current option settings\n");
  207. X        for (opp = optns; opp->name; opp++)
  208. X            printf("%-20s%s\n", opp->name,
  209. X                (opts[opp->id] == OPT_SET) ? "on" : "off");
  210. X    } else
  211. X        for (opp = optns; opp->name; opp++)
  212. X            if (opts[opp->id] == OPT_SET)
  213. X                puts(opp->name);
  214. X}
  215. X
  216. X/* add builtins to the command hash table */
  217. X
  218. Xvoid addbuiltins() /**/
  219. X{
  220. Xstruct cmdnam *c;
  221. Xstruct bincmd *b;
  222. Xint t0;
  223. X
  224. X    for (t0 = 0, b = builtins; b->name; b++,t0++)
  225. X        {
  226. X        c = (Cmdnam) zcalloc(sizeof *c);
  227. X        c->type = BUILTIN;
  228. X        c->u.binnum = t0;
  229. X        addhperm(b->name,c,cmdnamtab,freecmdnam);
  230. X        }
  231. X}
  232. X
  233. X/* enable */
  234. X
  235. Xint bin_enable(name,argv,ops,whocares) /**/
  236. Xchar *name;char **argv;char *ops;int whocares;
  237. X{
  238. Xstruct cmdnam *c;
  239. Xstruct bincmd *b;
  240. Xint t0,ret = 0;
  241. X
  242. X    for (; *argv; argv++)
  243. X        {
  244. X        for (t0 = 0, b = builtins; b->name; b++,t0++)
  245. X            if (!strcmp(*argv,b->name))
  246. X                break;
  247. X        if (!b->name)
  248. X            {
  249. X            zerrnam(name,"no such builtin: %s",*argv,0);
  250. X            ret = 1;
  251. X            }
  252. X        else
  253. X            {
  254. X            c = (Cmdnam) zcalloc(sizeof *c);
  255. X            c->type = BUILTIN;
  256. X            c->u.binnum = t0;
  257. X            addhperm(b->name,c,cmdnamtab,freecmdnam);
  258. X            }
  259. X        }
  260. X    return ret;
  261. X}
  262. X
  263. X/* :, true */
  264. X
  265. Xint bin_colon(name,argv,ops,whocares) /**/
  266. Xchar *name;char **argv;char *ops;int whocares;
  267. X{
  268. X    return 0;
  269. X}
  270. X
  271. X/* break, bye, continue, exit, logout, return, shift */
  272. X
  273. Xint bin_break(name,argv,ops,func) /**/
  274. Xchar *name;char **argv;char *ops;int func;
  275. X{
  276. Xint num = -1;
  277. X
  278. X    if (*argv)
  279. X        num = matheval(*argv);
  280. X    if ((func == BIN_BREAK || func == BIN_CONTINUE) && !loops)
  281. X        {
  282. X        if (func == BIN_CONTINUE)
  283. X            zerrnam(name,"not in loop",NULL,0);
  284. X        return 1;
  285. X        }
  286. X    switch (func)
  287. X        {
  288. X        case BIN_CONTINUE:
  289. X            contflag = 1;
  290. X        case BIN_BREAK:
  291. X            breaks = (num == -1) ? 1 : num;
  292. X            if (breaks > loops) breaks = loops;
  293. X            break;
  294. X        case BIN_LOGOUT:
  295. X            if (!islogin)
  296. X                {
  297. X                zerrnam(name,"not login shell",NULL,0);
  298. X                return 1;
  299. X                }
  300. X        case BIN_EXIT:
  301. X            zexit((num == -1) ? lastval : num);
  302. X            break;
  303. X        case BIN_RETURN:
  304. X            retflag = 1;
  305. X            return lastval = (num == -1) ? lastval : num;
  306. X        case BIN_SHIFT:
  307. X            {
  308. X            char **s;
  309. X
  310. X            if (num == -1)
  311. X                num = 1;
  312. X            if (num > arrlen(pparams))
  313. X                num = arrlen(pparams);
  314. X            permalloc();
  315. X            s = arrdup(pparams+num);
  316. X            heapalloc();
  317. X            freearray(pparams);
  318. X            pparams = s;
  319. X            break;
  320. X            }
  321. X        }
  322. X    return 0;
  323. X}
  324. X
  325. X/* bg, disown, fg, jobs, wait */
  326. X
  327. Xint bin_fg(name,argv,ops,func) /**/
  328. Xchar *name;char **argv;char *ops;int func;
  329. X{
  330. Xint job,lng,firstjob = -1,retval = 0;
  331. X
  332. X    if (ops['Z']) { if (*argv) strcpy(hackzero,*argv); return 0; }
  333. X    lng = (ops['l']) ? 1 : (ops['p']) ? 2 : 0;
  334. X    if ((func == BIN_FG || func == BIN_BG) && !jobbing)
  335. X        {
  336. X        zerrnam(name,"no job control in this shell.",NULL,0);
  337. X        return 1;
  338. X        }
  339. X    if (unset(NOTIFY)) scanjobs();
  340. X    if (!(jobtab[curjob].stat & STAT_INUSE))
  341. X        {
  342. X        curjob = prevjob; setprevjob();
  343. X        if (!(jobtab[curjob].stat & STAT_INUSE))
  344. X            curjob = prevjob; setprevjob();
  345. X        }
  346. X    if (func == BIN_JOBS)
  347. X        stopmsg = 2;
  348. X    if (!*argv)
  349. X        if (func == BIN_FG || func == BIN_BG)
  350. X            {
  351. X            if (curjob == -1 || curjob == thisjob)
  352. X                {
  353. X                zerrnam(name,"no current job",NULL,0);
  354. X                return 1;
  355. X                }
  356. X            firstjob = curjob;
  357. X            }
  358. X        else if (func == BIN_JOBS)
  359. X            {
  360. X            for (job = 0; job != MAXJOB; job++)
  361. X                if (job != thisjob && jobtab[job].stat)
  362. X                    printjob(job+jobtab,lng);
  363. X            return 0;
  364. X            }
  365. X        else
  366. X            {
  367. X            for (job = 0; job != MAXJOB; job++)
  368. X                if (job != thisjob && jobtab[job].stat)
  369. X                    waitjob(job);
  370. X            return lastval;
  371. X            }
  372. X    for (; (firstjob != -1) || *argv; ( void ) (*argv && argv++))
  373. X        {
  374. X        int stopped,ocj = thisjob;
  375. X
  376. X        if (func == BIN_WAIT && isanum(*argv)) {
  377. X            waitforpid((long) atoi(*argv));
  378. X            retval = lastval;
  379. X            thisjob = ocj;
  380. X            continue;
  381. X        }
  382. X        job = (*argv) ? getjob(*argv,name) : firstjob;
  383. X        firstjob = -1;
  384. X        if (job == -1)
  385. X            break;
  386. X        if (!(jobtab[job].stat & STAT_INUSE))
  387. X            {
  388. X            zerrnam(name,"no such job: %d",0,job);
  389. X            return 1;
  390. X            }
  391. X        switch (func)
  392. X            {
  393. X            case BIN_FG:
  394. X            case BIN_BG:
  395. X                if (stopped = (jobtab[job].stat & STAT_STOPPED))
  396. X                    makerunning(jobtab+job);
  397. X                else if (func == BIN_BG)
  398. X                    {
  399. X                    zerrnam(name,"job already in background",NULL,0);
  400. X                    thisjob = ocj;
  401. X                    return 1;
  402. X                    }
  403. X                if (curjob == job)
  404. X                    {
  405. X                    curjob = prevjob;
  406. X                    prevjob = (func == BIN_BG) ? -1 : job;
  407. X                    }
  408. X                if (prevjob == job)
  409. X                    prevjob = -1;
  410. X                if (prevjob == -1)
  411. X                    setprevjob();
  412. X                if (curjob == -1)
  413. X                    {
  414. X                    curjob = prevjob;
  415. X                    setprevjob();
  416. X                    }
  417. X                printjob(jobtab+job,(stopped) ? -1 : 0);
  418. X                if (func == BIN_FG)
  419. X                    {
  420. X                    thisjob = job;
  421. X                    if (strcmp(jobtab[job].pwd,pwd))
  422. X                        {
  423. X                        printf("(pwd : ");
  424. X                        printdir(jobtab[job].pwd);
  425. X                        printf(")\n");
  426. X                        }
  427. X                    fflush(stdout);
  428. X                    attachtty(jobtab[job].gleader);
  429. X                    }
  430. X                if (stopped)
  431. X                    killpg(jobtab[job].gleader,SIGCONT);
  432. X                if (func == BIN_FG)
  433. X                    waitjobs();
  434. X                break;
  435. X            case BIN_JOBS:
  436. X                printjob(job+jobtab,lng);
  437. X                break;
  438. X            case BIN_WAIT:
  439. X                waitjob(job);
  440. X                retval = lastval;
  441. X                break;
  442. X            case BIN_DISOWN:
  443. X                {
  444. X                static struct job zero;
  445. X                jobtab[job] = zero;
  446. X                break;
  447. X                }
  448. X            }
  449. X        thisjob = ocj;
  450. X        }
  451. X    return retval;
  452. X}
  453. X
  454. X/* false, let */
  455. X
  456. Xint bin_let(name,argv,ops,func) /**/
  457. Xchar *name;char **argv;char *ops;int func;
  458. X{
  459. Xlong val = 0;
  460. X
  461. X    while (*argv)
  462. X        val = matheval(*argv++);
  463. X    return !val;
  464. X}
  465. X
  466. X/* print the directory stack */
  467. X
  468. Xstatic void pdstack()
  469. X{
  470. XLknode node;
  471. X
  472. X    printdir(pwd);
  473. X    for (node = firstnode(dirstack); node; incnode(node))
  474. X        {
  475. X        putchar(' ');
  476. X        printdir(getdata(node));
  477. X        }
  478. X    putchar('\n');
  479. X}
  480. X
  481. X/* exit the shell */
  482. X
  483. Xint zexit(val) /**/
  484. Xint val;
  485. X{
  486. X    if (isset(MONITOR))
  487. X        if (!stopmsg) {
  488. X            checkjobs();
  489. X            if (stopmsg) {
  490. X                stopmsg = 2;
  491. X                return 1;
  492. X            }
  493. X        } else killrunjobs();
  494. X    savehistfile(getsparam("HISTFILE"),0,0);
  495. X    if (islogin && unset(NORCS))
  496. X        sourcehome(".zlogout");
  497. X    if (sigtrapped[SIGEXIT])
  498. X        dotrap(SIGEXIT);
  499. X    exit(val); return 0;
  500. X}
  501. X
  502. X/* identify an option name */
  503. X
  504. Xint optlookup(s) /**/
  505. Xchar *s;
  506. X{
  507. Xchar *t;
  508. Xstruct option *o;
  509. X
  510. X    t = s = strdup(s);
  511. X    while (*t)
  512. X        if (*t == '_')
  513. X            chuck(t);
  514. X        else {
  515. X            *t = tulower(*t);
  516. X            t++;
  517. X        }
  518. X    for (o = optns; o->name; o++)
  519. X        if (!strcmp(o->name,s))
  520. X            return o->id;
  521. X    return -1;
  522. X}
  523. X
  524. X/* setopt, unsetopt */
  525. X
  526. Xint bin_setopt(nam,args,ops,isun) /**/
  527. Xchar *nam;char **args;char *ops;int isun;
  528. X{
  529. Xstruct option *opp;
  530. Xint c;
  531. X
  532. X    if (!ops['@'] && !*args) {
  533. X        if (!isun)
  534. X            prtopt();
  535. X        return 0;
  536. X    }
  537. X    for (opp = optns; opp->name; opp++)
  538. X        if (ops[opp->id] == 1+isun)
  539. X            opts[opp->id] = OPT_SET;
  540. X        else if (ops[opp->id] == 2-isun)
  541. X            opts[opp->id] = OPT_UNSET;
  542. X    while (*args) {
  543. X        c = optlookup(*args++);
  544. X        if (c != -1) {
  545. X            if (c == INTERACTIVE || c == MONITOR)
  546. X                zerrnam(nam,"can't change that option",NULL,0);
  547. X            else
  548. X                opts[c] = (isun) ? OPT_UNSET : OPT_SET;
  549. X        } else {
  550. X            zerrnam(nam,"no such option: %s",args[-1],0);
  551. X            return 1;
  552. X        }
  553. X    }
  554. X    return 0;
  555. X}
  556. X
  557. X/* execute func on each member of the hash table ht */
  558. X
  559. Xvoid listhtable(ht,func) /**/
  560. XHashtab ht;HFunc func;
  561. X{
  562. Xint t0;
  563. Xstruct hashnode *hn;
  564. X
  565. X    for (t0 = ht->hsize-1; t0 >= 0; t0--)
  566. X        for (hn = ht->nodes[t0]; hn; hn = hn->next)
  567. X            func(hn->nam,(char *) hn);
  568. X}
  569. X
  570. X/* print a shell function (used with listhtable) */
  571. X
  572. Xvoid pshfunc(s,cc) /**/
  573. Xchar *s;Cmdnam cc;
  574. X{
  575. Xchar *t;
  576. X
  577. X    if (cc->type != SHFUNC)
  578. X        return;
  579. X    if (showflag && (cc->flags & showflag2) != showflag2)
  580. X        return;
  581. X    if (cc->flags & PMFLAG_u)
  582. X        printf("undefined ");
  583. X    if (cc->flags & PMFLAG_t)
  584. X        printf("traced ");
  585. X    if (!cc->u.list || !showflag) {
  586. X        printf("%s ()\n",s);
  587. X        return;
  588. X    }
  589. X    t = getpermtext((vptr) (cc->u.list));
  590. X    printf("%s () {\n\t%s\n}\n",s,t);
  591. X    free(t);
  592. X}
  593. X
  594. Xvoid niceprint(s) /**/
  595. Xchar *s;
  596. X{
  597. X    niceprintf(s,stdout);
  598. X}
  599. X
  600. Xvoid niceprintf(s,f) /**/
  601. Xchar *s;FILE *f;
  602. X{
  603. X    for (; *s; s++)
  604. X        {
  605. X        if (isprint(*s))
  606. X            fputc(*s,f);
  607. X        else if (*s == '\n')
  608. X            {
  609. X            putc('\\',f);
  610. X            putc('n',f);
  611. X            }
  612. X        else
  613. X            {
  614. X            putc('^',f);
  615. X            fputc(*s | 0x40,f);
  616. X            }
  617. X        }
  618. X}
  619. X
  620. Xint bin_umask(nam,args,ops,func) /**/
  621. Xchar *nam;char **args;char *ops;int func;
  622. X{
  623. Xint um;
  624. Xchar *s = *args;
  625. X
  626. X    um = umask(0);
  627. X    umask(um);
  628. X    if (!s)
  629. X        {
  630. X        printf("%03o\n",um);
  631. X        return 0;
  632. X        }
  633. X    if (idigit(*s))
  634. X        {
  635. X        um = zstrtol(s,&s,8);
  636. X        if (*s)
  637. X            {
  638. X            zerrnam(nam,"bad umask",NULL,0);
  639. X            return 1;
  640. X            }
  641. X        }
  642. X    else
  643. X        {
  644. X        int whomask,op,mask;
  645. X
  646. X        for (;;)
  647. X            {
  648. X            if (*s == 'u')
  649. X                s++, whomask = 0100;
  650. X            else if (*s == 'g')
  651. X                s++, whomask = 0010;
  652. X            else if (*s == 'o')
  653. X                s++, whomask = 0001;
  654. X            else
  655. X                whomask = 0111;
  656. X            op = *s++;
  657. X            if (!(op == '+' || op == '-' || op == '='))
  658. X                {
  659. X                zerrnam(nam,"bad symbolic mode operator: %c",NULL,op);
  660. X                return 1;
  661. X                }
  662. X            mask = whomask;
  663. X            if (*s == 'r')
  664. X                mask *= 04;
  665. X            else if (*s == 'w')
  666. X                mask *= 02;
  667. X            else if (*s != 'x')
  668. X                {
  669. X                zerrnam(nam,"bad symbolic mode permission: %c",NULL,*s);
  670. X                return 1;
  671. X                }
  672. X            if (op == '+')
  673. X                um |= mask;
  674. X            else if (op == '-')
  675. X                um &= ~mask;
  676. X            else /* op == '=' */
  677. X                um = (um & ~(whomask*07)) | mask;
  678. X            if (*++s == ',')
  679. X                s++;
  680. X            else
  681. X                break;
  682. X            }
  683. X        if (*s)
  684. X            {
  685. X            zerrnam(nam,"bad character in symbolic mode: %c",NULL,*s);
  686. X            return 1;
  687. X            }
  688. X        }
  689. X    umask(um);
  690. X    return 0;
  691. X}
  692. X
  693. X/* type, whence, which */
  694. X
  695. Xint bin_whence(nam,argv,ops,func) /**/
  696. Xchar *nam;char **argv;char *ops;int func;
  697. X{
  698. Xstruct cmdnam *chn;
  699. Xstruct alias *a;
  700. Xint retval = 0;
  701. Xint csh = ops['c'],all = ops['a'];
  702. Xint v = ops['v'] || csh;
  703. Xchar *cnam;
  704. X
  705. X    for (; *argv; argv++) {
  706. X        if (!ops['p'] && (a = (Alias) gethnode(*argv,aliastab))) {
  707. X            if (a->cmd < 0)
  708. X                printf((csh) ? "%s: shell reserved word\n" :
  709. X                    (v) ? "%s is a reserved word\n" : "%s\n",*argv);
  710. X            else if (!v)
  711. X                puts(a->text);
  712. X            else if (a->cmd)
  713. X                printf((csh) ? "%s: aliased to %s\n" :
  714. X                    "%s is an alias for %s\n",*argv,a->text);
  715. X            else
  716. X                printf((csh) ? "%s: globally aliased to %s\n" :
  717. X                    "%s is a global alias for %s\n",*argv,a->text);
  718. X            retval = 0;
  719. X            if (!all) continue;
  720. X        }
  721. X        if (!ops['p'] && (chn = (Cmdnam) gethnode(*argv,cmdnamtab)) &&
  722. X                (chn->type == SHFUNC || chn->type == BUILTIN)) {
  723. X            if (chn->type == SHFUNC) {
  724. X                if (csh || ops['f']) {
  725. X                    showflag = 1; showflag2 = 0;
  726. X                    pshfunc(*argv,chn);
  727. X                } else {
  728. X                    printf((v) ? "%s is a function\n" : "%s\n",*argv);
  729. X                }
  730. X            } else
  731. X                printf((csh) ? "%s: shell built-in command\n" :
  732. X                    (v) ? "%s is a shell builtin\n" : "%s\n",*argv);
  733. X            retval = 0;
  734. X            if (!all) continue;
  735. X        }
  736. X        if (all) {
  737. X            char **pp,buf[MAXPATHLEN],*z;
  738. X            for (pp = path; *pp; pp++) {
  739. X                z = buf;
  740. X                strucpy(&z,*pp);
  741. X                *z++ = '/';
  742. X                strcpy(z,*argv);
  743. X                if (iscom(buf)) {
  744. X                    if (v && !csh) printf("%s is %s\n",*argv,buf);
  745. X                    else puts(buf);
  746. X                    retval = 0;
  747. X                }
  748. X            }
  749. X        } else if (!(cnam = findcmd(*argv))) {
  750. X            if (v) printf("%s not found\n",*argv);
  751. X            retval = 1;
  752. X            break;
  753. X        } else {
  754. X            if (v && !csh) printf("%s is %s\n",*argv,cnam);
  755. X            else puts(cnam);
  756. X            retval = 0;
  757. X        }
  758. X    }
  759. X    return retval;
  760. X}
  761. X
  762. X/* cd, chdir, pushd, popd */
  763. X
  764. Xint bin_cd(nam,argv,ops,func) /**/
  765. Xchar *nam;char **argv;char *ops;int func;
  766. X{
  767. Xchar *dest;
  768. X
  769. X    if (func == BIN_CD && isset(AUTOPUSHD))
  770. X        func = BIN_PUSHD;
  771. X    dest = cd_get_dest(nam,argv,ops,func);
  772. X    if (!dest) return 1;
  773. X    dest = cd_do_chdir(nam,dest);
  774. X    if (!dest) return 1;
  775. X    cd_new_pwd(func,dest);
  776. X    return 0;
  777. X}
  778. X
  779. Xchar *cd_get_dest(nam,argv,ops,func) /**/
  780. Xchar *nam;char **argv;char *ops;int func;
  781. X{
  782. Xchar *dest;
  783. X
  784. X    if (!argv[0])
  785. X        if (func == BIN_CD || (func == BIN_PUSHD && isset(PUSHDTOHOME)
  786. X                || !full(dirstack)))
  787. X            dest = home;
  788. X        else
  789. X            dest = getnode(dirstack);
  790. X    else if (!argv[1]) {
  791. X        Lknode n;
  792. X        int dd;
  793. X
  794. X        if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '-' : '+')) {
  795. X            dd = atoi(argv[0]+1)-1;
  796. X            if (dd < 0) {
  797. X                zerrnam(nam,"bad directory specification",NULL,0);
  798. X                return NULL;
  799. X            }
  800. X            for (n = firstnode(dirstack); n && dd; dd--, incnode(n));
  801. X            if (!n) {
  802. X                zerrnam(nam,"no such entry in dir stack",NULL,0);
  803. X                return NULL;
  804. X            }
  805. X            dest = remnode(dirstack,n);
  806. X        } else if (argv[0][1] && argv[0][0] == (isset(PUSHDMINUS) ? '+' : '-')) {
  807. X            dd = atoi(argv[0]+1);
  808. X            for (n = lastnode(dirstack); n != (Lknode) dirstack && dd;
  809. X                    dd--, n = prevnode(n));
  810. X            if (n == (Lknode) dirstack) {
  811. X                zerrnam(nam,"no such entry in dir stack",NULL,0);
  812. X                return NULL;
  813. X            }
  814. X            dest = remnode(dirstack,n);
  815. X        } else {
  816. X            if (!strcmp(argv[0],"-")) printdircr(dest = oldpwd);
  817. X            else dest = argv[0];
  818. X        }
  819. X    } else {
  820. X        char *u;
  821. X        int len1,len2,len3;
  822. X
  823. X        if (!(u = ztrstr(pwd,argv[0]))) {
  824. X            zerrnam(nam,"string not in pwd: %s",argv[0],0);
  825. X            return NULL;
  826. X        }
  827. X        len1 = strlen(argv[0]);
  828. X        len2 = strlen(argv[1]);
  829. X        len3 = u-pwd;
  830. X        dest = alloc(len3+len2+strlen(u+len1)+1);
  831. X        strncpy(dest,pwd,len3);
  832. X        strcpy(dest+len3,argv[1]);
  833. X        strcat(dest,u+len1);
  834. X        printdircr(dest);
  835. X    }
  836. X    return dest;
  837. X}
  838. X
  839. Xchar *cd_do_chdir(cnam,dest) /**/
  840. Xchar *cnam; char *dest;
  841. X{
  842. Xint hasdot = 0, eno = ENOENT;
  843. Xchar **pp,*ret;
  844. X
  845. X    if (*dest == '/') {
  846. X        if (ret = cd_try_chdir(NULL,dest)) return ret;
  847. X        zerrnam(cnam,"%e: %s",dest,errno);
  848. X        return NULL;
  849. X    }
  850. X    for (pp = cdpath; *pp; pp++)
  851. X        if ((*pp)[0] == '.' && (*pp)[1] == '\0') hasdot = 1;
  852. X    if (!hasdot) {
  853. X        if (ret = cd_try_chdir(NULL,dest)) return ret;
  854. X        if (errno != ENOENT) eno = errno;
  855. X    }
  856. X    for (pp = cdpath; *pp; pp++) {
  857. X        if (ret = cd_try_chdir(*pp,dest)) {
  858. X            if (strcmp(*pp,".")) {
  859. X                printdircr(ret);
  860. X            }
  861. X            return ret;
  862. X        }
  863. X        if (errno != ENOENT) eno = errno;
  864. X    }
  865. X    if (isset(CDABLEVARS)) {
  866. X        char *s = getsparam(dest);
  867. X        if (s && *s == '/' && chdir(s) != -1) {
  868. X            printdircr(s);
  869. X            return s;
  870. X        }
  871. X        if (errno != ENOENT) eno = errno;
  872. X    }
  873. X    zerrnam(cnam,"%e: %s",dest,eno);
  874. X    return NULL;
  875. X}
  876. X
  877. Xchar *cd_try_chdir(pfix,dest) /**/
  878. Xchar *pfix; char *dest;
  879. X{
  880. Xstatic char buf[MAXPATHLEN], buf2[MAXPATHLEN];
  881. Xchar *s;
  882. Xint dotsct;
  883. X
  884. X    if (pfix) sprintf(buf,"%s/%s",(!strcmp("/",pfix)) ? "" : pfix,dest); 
  885. X    else strcpy(buf,dest);
  886. X    dotsct = fixdir(buf2,buf);
  887. X    if (buf2[0] == '/') return (chdir(buf2) == -1) ? NULL : buf2;
  888. X    if (!dotsct) {
  889. X        if (chdir((*buf2) ? buf2 : ".") == -1) return NULL;
  890. X        if (*buf2) sprintf(buf,"%s/%s",(!strcmp("/",pwd)) ? "" : pwd,buf2);
  891. X        else strcpy(buf,pwd);
  892. X        return buf;
  893. X    }
  894. X    strcpy(buf,pwd);
  895. X    s = buf+strlen(buf)-1;
  896. X    while (dotsct--) while (s != buf) if (*--s == '/') break;
  897. X    if (s == buf || *buf2) s++;
  898. X    strcpy(s,buf2);
  899. X    if (chdir(buf) != -1 || chdir(dest) != -1) return buf;
  900. X    return NULL;
  901. X}
  902. X
  903. Xint fixdir(d,s) /**/
  904. Xchar *d; char *s;
  905. X{
  906. Xint ct = 0;
  907. Xchar *d0 = d;
  908. X
  909. X#ifdef HAS_RFS
  910. X    if (*s == '/' && s[1] == '.' && s[2] == '.') {
  911. X        *d++ = '/'; *d++ = '.'; *d++ = '.';
  912. X        s += 3;
  913. X    }
  914. X#endif
  915. X    for (;;) {
  916. X        if (*s == '/') {
  917. X            *d++ = *s++;
  918. X            while (*s == '/') s++;
  919. X        }
  920. X        if (!*s) {
  921. X            while (d > d0+1 && d[-1] == '/') d--;
  922. X            *d = '\0';
  923. X            return ct;
  924. X        }
  925. X        if (s[0] == '.' && s[1] == '.' && (s[2] == '\0' || s[2] == '/')) {
  926. X            if (d > d0+1) {
  927. X                for (d--; d > d0+1 && d[-1] != '/'; d--);
  928. X            } else ct++;
  929. X            s += 2; if (*s) s++;
  930. X        } else if (s[0] == '.' && (s[1] == '/' || s[1] == '\0')) {
  931. X            s++; if (*s) s++;
  932. X        } else {
  933. X            while (*s != '/' && *s != '\0') *d++ = *s++;
  934. X        }
  935. X    }
  936. X}
  937. X
  938. Xvoid cd_new_pwd(func,s) /**/
  939. Xint func; char *s;
  940. X{
  941. XParam pm;
  942. XList l;
  943. X
  944. X    oldpwd = pwd;
  945. X    if (isset(CHASELINKS))
  946. X        pwd = findpwd(s);
  947. X    else
  948. X        pwd = ztrdup(s);
  949. X    if ((pm = gethnode("PWD", paramtab)) &&
  950. X         (pm->flags & PMFLAG_x) && pm->env)
  951. X        pm->env = replenv(pm->env,pwd);
  952. X    if ((pm = gethnode("OLDPWD", paramtab)) &&
  953. X         (pm->flags & PMFLAG_x) && pm->env)
  954. X        pm->env = replenv(pm->env,oldpwd);
  955. X    if (func == BIN_PUSHD) {
  956. X        permalloc();
  957. X        if (isset(PUSHDIGNOREDUPS)) {
  958. X            Lknode n;
  959. X            for (n = firstnode(dirstack); n; incnode(n))
  960. X                if (!strcmp(oldpwd,getdata(n))) {
  961. X                    free(remnode(dirstack,n)); break;
  962. X                }
  963. X        }
  964. X        pushnode(dirstack,oldpwd);
  965. X        heapalloc();
  966. X    }
  967. X    if (unset(PUSHDSILENT) && func != BIN_CD && isset(INTERACTIVE))
  968. X        pdstack();
  969. X    if (l = getshfunc("chpwd")) {
  970. X        fflush(stdout); fflush(stderr);
  971. X        doshfuncnoval(dupstruct(l),NULL,0);
  972. X    }
  973. X    if (dirstacksize != -1 && countnodes(dirstack) >= dirstacksize) {
  974. X        if (dirstacksize < 2)
  975. X            dirstacksize = 2;
  976. X        else
  977. X            free(remnode(dirstack,lastnode(dirstack)));
  978. X    }
  979. X}
  980. X
  981. Xvoid convertwd(s,t,off) /**/
  982. Xchar *s; char *t; int off;
  983. X{
  984. Xchar *u,*start;
  985. X
  986. X    *t++ = '/';
  987. X    start = t;
  988. X    while (off--) *t++ = *s++;
  989. X    for (;;) {
  990. X        while (*s == '/') s++;
  991. X        for (u = s; *u && *u != '/'; u++);
  992. X        if (!strncmp(s,".",u-s)) {
  993. X            ;
  994. X        } else if (!strncmp(s,"..",u-s)) {
  995. X            while (t != start && *--t != '/');
  996. X        } else {
  997. X            if (t != start) *t++ = '/';
  998. X            struncpy(&t,s,u-s);
  999. X        }
  1000. X        if (!*u) break;
  1001. X        s = u;
  1002. X    }
  1003. X    *t = '\0';
  1004. X}
  1005. X
  1006. Xint bin_rehash(name,argv,ops,func) /**/
  1007. Xchar *name;char **argv;char *ops;int func;
  1008. X{
  1009. X    newcmdnamtab();
  1010. X    if (ops['f']) fullhash();
  1011. X    return 0;
  1012. X}
  1013. X
  1014. Xint bin_hash(name,argv,ops,func) /**/
  1015. Xchar *name;char **argv;char *ops;int func;
  1016. X{
  1017. Xstruct cmdnam *chn;
  1018. X
  1019. X    chn = (Cmdnam) zcalloc(sizeof *chn);
  1020. X    chn->type = EXCMD;
  1021. X    chn->pcomp = NULL; /* this is probably a bug ! */
  1022. X    chn->u.nam = ztrdup(argv[1]);
  1023. X    addhnode(ztrdup(argv[0]),chn,cmdnamtab,freecmdnam);
  1024. X    return 0;
  1025. X}
  1026. X
  1027. X/* != 0 if s is a prefix of t */
  1028. X
  1029. Xint prefix(s,t) /**/
  1030. Xchar *s;char *t;
  1031. X{
  1032. X    while (*s && *t && *s == *t) s++,t++;
  1033. X    return (!*s);
  1034. X}
  1035. X
  1036. X/* convert %%, %1, %foo, %?bar? to a job number */
  1037. X
  1038. Xint getjob(s,prog) /**/
  1039. Xchar *s;char *prog;
  1040. X{
  1041. Xint t0,retval;
  1042. X
  1043. X    if (*s != '%')
  1044. X        goto jump;
  1045. X    s++;
  1046. X    if (*s == '%' || *s == '+' || !*s)
  1047. X        {
  1048. X        if (curjob == -1)
  1049. X            {
  1050. X            zerrnam(prog,"no current job",NULL,0);
  1051. X            retval = -1; goto done;
  1052. X            }
  1053. X        retval = curjob; goto done;
  1054. X        }
  1055. X    if (*s == '-')
  1056. X        {
  1057. X        if (prevjob == -1)
  1058. X            {
  1059. X            zerrnam(prog,"no previous job",NULL,0);
  1060. X            retval = -1; goto done;
  1061. X            }
  1062. X        retval = prevjob; goto done;
  1063. X        }
  1064. X    if (idigit(*s))
  1065. X        {
  1066. X        t0 = atoi(s);
  1067. X        if (t0 && t0 < MAXJOB && jobtab[t0].stat && t0 != thisjob)
  1068. X            { retval = t0; goto done; }
  1069. X        zerrnam(prog,"no such job",NULL,0);
  1070. X        retval = -1; goto done;
  1071. X        }
  1072. X    if (*s == '?')
  1073. X        {
  1074. X        struct process *pn;
  1075. X
  1076. X        for (t0 = MAXJOB-1; t0 >= 0; t0--)
  1077. X            if (jobtab[t0].stat && t0 != thisjob)
  1078. X                for (pn = jobtab[t0].procs; pn; pn = pn->next)
  1079. X                    if (ztrstr(pn->text,s+1))
  1080. X                        { retval = t0; goto done; }
  1081. X        zerrnam(prog,"job not found: %s",s,0);
  1082. X        retval = -1; goto done;
  1083. X        }
  1084. Xjump:
  1085. X    if ((t0 = findjobnam(s)) != -1)
  1086. X        { retval = t0; goto done; }
  1087. X    zerrnam(prog,"job not found: %s",s,0);
  1088. X    retval = -1;
  1089. Xdone:
  1090. X    return retval;
  1091. X}
  1092. X
  1093. X/* find a job named s */
  1094. X
  1095. Xint findjobnam(s) /**/
  1096. Xchar *s;
  1097. X{
  1098. Xint t0;
  1099. X
  1100. X    for (t0 = MAXJOB-1; t0 >= 0; t0--)
  1101. X        if (jobtab[t0].stat && jobtab[t0].procs && t0 != thisjob && 
  1102. X                jobtab[t0].procs->text && prefix(s,jobtab[t0].procs->text))
  1103. X            return t0;
  1104. X    return -1;
  1105. X}
  1106. X
  1107. Xint isanum(s) /**/
  1108. Xchar *s;
  1109. X{
  1110. X    while (*s == '-' || idigit(*s)) s++;
  1111. X    return *s == '\0';
  1112. X}
  1113. X
  1114. Xint bin_kill(nam,argv,ops,func) /**/
  1115. Xchar *nam;char **argv;char *ops;int func;
  1116. X{
  1117. Xint sig = SIGTERM;
  1118. Xint retval = 0;
  1119. X
  1120. X    if (*argv && **argv == '-') {
  1121. X        if (idigit((*argv)[1]))
  1122. X            sig = atoi(*argv+1);
  1123. X        else {
  1124. X            if ((*argv)[1] == 'l' && (*argv)[2] == '\0') {
  1125. X                printf("%s",sigs[1]);
  1126. X                for (sig = 2; sig != SIGCOUNT; sig++)
  1127. X                    printf(" %s",sigs[sig]);
  1128. X                putchar('\n');
  1129. X                return 0;
  1130. X            }
  1131. X            for (sig = 0; sig != SIGCOUNT; sig++)
  1132. X                if (!strcmp(sigs[sig],*argv+1)) break;
  1133. X            if (sig == SIGCOUNT) {
  1134. X                zerrnam(nam,"unknown signal: SIG%s",*argv+1,0);
  1135. X                zerrnam(nam,"type kill -l for a List of signals",NULL,0);
  1136. X                return 1;
  1137. X            }
  1138. X        }
  1139. X        argv++;
  1140. X    }
  1141. X    for (; *argv; argv++) {
  1142. X        if (**argv == '%') {
  1143. X            int p = getjob(*argv,"kill");
  1144. X
  1145. X            if (p == -1) {
  1146. X                retval = 1;
  1147. X                continue;
  1148. X            }
  1149. X            if (killjb(jobtab+p,sig) == -1) {
  1150. X                zerrnam("kill","kill failed: %e",NULL,errno);
  1151. X                retval = 1;
  1152. X                continue;
  1153. X            }
  1154. X            if (jobtab[p].stat & STAT_STOPPED) {
  1155. X                if (sig == SIGCONT)
  1156. X                    jobtab[p].stat &= ~STAT_STOPPED;
  1157. X                if (sig != SIGKILL && sig != SIGCONT && sig != SIGTSTP
  1158. X                        && sig != SIGTTOU && sig != SIGTTIN && sig != SIGSTOP)
  1159. X                    killjb(jobtab+p,SIGCONT);
  1160. X            }
  1161. X        } else if (!isanum(*argv)) {
  1162. X            zerrnam("kill","illegal pid: %s",*argv,0);
  1163. X        } else if (kill(atoi(*argv),sig) == -1) {
  1164. X                zerrnam("kill","kill failed: %e",NULL,errno);
  1165. X                retval = 1;
  1166. X        }
  1167. X    }
  1168. X    return 0;
  1169. X}
  1170. X
  1171. Xstatic char *recs[] = {
  1172. X    "cputime","filesize","datasize","stacksize","coredumpsize",
  1173. X    "resident","descriptors"
  1174. X    };
  1175. X
  1176. Xint bin_limit(nam,argv,ops,func) /**/
  1177. Xchar *nam;char **argv;char *ops;int func;
  1178. X{
  1179. X#ifndef RLIM_INFINITY
  1180. X    zerrnam(nam,"not available on this system",NULL,0);
  1181. X    return 1;
  1182. X#else
  1183. Xchar *s;
  1184. Xint hard = ops['h'],t0,lim;
  1185. Xlong val;
  1186. X
  1187. X    if (ops['s'])
  1188. X        {
  1189. X        if (*argv)
  1190. X            zerrnam(nam,"arguments after -s ignored",NULL,0);
  1191. X        for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1192. X            if (setrlimit(t0,limits+t0) < 0)
  1193. X                zerrnam(nam,"setrlimit failed: %e",NULL,errno);
  1194. X        return 0;
  1195. X        }
  1196. X    if (!*argv)
  1197. X        {
  1198. X        showlimits(hard,-1);
  1199. X        return 0;
  1200. X        }
  1201. X    while (s = *argv++)
  1202. X        {
  1203. X        for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1204. X            if (!strncmp(recs[t0],s,strlen(s)))
  1205. X                {
  1206. X                if (lim != -1)
  1207. X                    lim = -2;
  1208. X                else
  1209. X                    lim = t0;
  1210. X                }
  1211. X        if (lim < 0)
  1212. X            {
  1213. X            zerrnam("limit",
  1214. X                (lim == -2) ? "ambiguous resource specification: %s"
  1215. X                                : "no such resource: %s",s,0);
  1216. X            return 1;
  1217. X            }
  1218. X        if (!(s = *argv++))
  1219. X            {
  1220. X            showlimits(hard,lim);
  1221. X            return 0;
  1222. X            }
  1223. X        if (!lim)
  1224. X            {
  1225. X            val = zstrtol(s,&s,10);
  1226. X            if (*s)
  1227. X                if ((*s == 'h' || *s == 'H') && !s[1])
  1228. X                    val *= 3600L;
  1229. X                else if ((*s == 'm' || *s == 'M') && !s[1])
  1230. X                    val *= 60L;
  1231. X                else if (*s == ':')
  1232. X                    val = val*60+zstrtol(s+1,&s,10);
  1233. X                else
  1234. X                    {
  1235. X                    zerrnam("limit","unknown scaling factor: %s",s,0);
  1236. X                    return 1;
  1237. X                    }
  1238. X            }
  1239. X#ifdef RLIMIT_NOFILE
  1240. X        else if (lim == RLIMIT_NOFILE)
  1241. X            val = zstrtol(s,&s,10);
  1242. X#endif
  1243. X        else
  1244. X            {
  1245. X            val = zstrtol(s,&s,10);
  1246. X            if (!*s || ((*s == 'k' || *s == 'K') && !s[1]))
  1247. X                val *= 1024L;
  1248. X            else if ((*s == 'M' || *s == 'm') && !s[1])
  1249. X                val *= 1024L*1024;
  1250. X            else
  1251. X                {
  1252. X                zerrnam("limit","unknown scaling factor: %s",s,0);
  1253. X                return 1;
  1254. X                }
  1255. X            }
  1256. X        if (hard)
  1257. X            if (val > limits[lim].rlim_max && geteuid())
  1258. X                {
  1259. X                zerrnam("limit","can't raise hard limits",NULL,0);
  1260. X                return 1;
  1261. X                }
  1262. X            else
  1263. X                {
  1264. X                limits[lim].rlim_max = val;
  1265. X                if (limits[lim].rlim_max < limits[lim].rlim_cur)
  1266. X                    limits[lim].rlim_cur = limits[lim].rlim_max;
  1267. X                }
  1268. X        else
  1269. X            if (val > limits[lim].rlim_max)
  1270. X                {
  1271. X                zerrnam("limit","limit exceeds hard limit",NULL,0);
  1272. X                return 1;
  1273. X                }
  1274. X            else
  1275. X                limits[lim].rlim_cur = val;
  1276. X        }
  1277. X    return 0;
  1278. X#endif
  1279. X}
  1280. X
  1281. Xint bin_unlimit(nam,argv,ops,func) /**/
  1282. Xchar *nam;char **argv;char *ops;int func;
  1283. X{
  1284. X#ifndef RLIM_INFINITY
  1285. X    zerrnam(nam,"not available on this system",NULL,0);
  1286. X    return 1;
  1287. X#else
  1288. Xint hard = ops['h'],t0,lim;
  1289. X
  1290. X    if (hard && geteuid())
  1291. X        {
  1292. X        zerrnam(nam,"can't remove hard limits",NULL,0);
  1293. X        return 1;
  1294. X        }
  1295. X    if (!*argv)
  1296. X        {
  1297. X        for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1298. X            {
  1299. X            if (hard)
  1300. X                limits[t0].rlim_max = RLIM_INFINITY;
  1301. X            else
  1302. X                limits[t0].rlim_cur = limits[t0].rlim_max;
  1303. X            }
  1304. X        return 0;
  1305. X        }
  1306. X    for (; *argv; argv++)
  1307. X        {
  1308. X        for (lim = -1, t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1309. X            if (!strncmp(recs[t0],*argv,strlen(*argv)))
  1310. X                {
  1311. X                if (lim != -1)
  1312. X                    lim = -2;
  1313. X                else
  1314. X                    lim = t0;
  1315. X                }
  1316. X        if (lim < 0)
  1317. X            {
  1318. X            zerrnam(nam,
  1319. X                (lim == -2) ? "ambiguous resource specification: %s"
  1320. X                                : "no such resource: %s",*argv,0);
  1321. X            return 1;
  1322. X            }
  1323. X        if (hard)
  1324. X            limits[lim].rlim_max = RLIM_INFINITY;
  1325. X        else
  1326. X            limits[lim].rlim_cur = limits[lim].rlim_max;
  1327. X        }
  1328. X    return 0;
  1329. X#endif
  1330. X}
  1331. X
  1332. Xvoid showlimits(hard,lim) /**/
  1333. Xint hard;int lim;
  1334. X{
  1335. Xint t0;
  1336. Xlong val;
  1337. X
  1338. X#ifdef RLIM_INFINITY
  1339. X    for (t0 = 0; t0 != RLIM_NLIMITS; t0++)
  1340. X        if (t0 == lim || lim == -1)
  1341. X            {
  1342. X            printf("%-16s",recs[t0]);
  1343. X            val = (hard) ? limits[t0].rlim_max : limits[t0].rlim_cur;
  1344. X            if (val == RLIM_INFINITY)
  1345. X                printf("unlimited\n");
  1346. X            else if (!t0)
  1347. X                printf("%d:%02d:%02d\n",(int) (val/3600),
  1348. X                    (int) (val/60) % 60,(int) (val % 60));
  1349. X#ifdef RLIMIT_NOFILE
  1350. X            else if (t0 == RLIMIT_NOFILE)
  1351. X                printf("%d\n",(int) val);
  1352. X#endif
  1353. X            else if (val >= 1024L*1024L)
  1354. X                printf("%ldMb\n",val/(1024L*1024L));
  1355. X            else
  1356. X                printf("%ldKb\n",val/1024L);
  1357. X            }
  1358. X#endif
  1359. X}
  1360. X
  1361. Xint bin_sched(nam,argv,ops,func) /**/
  1362. Xchar *nam;char **argv;char *ops;int func;
  1363. X{
  1364. Xchar *s = *argv++;
  1365. Xtime_t t;
  1366. Xlong h,m;
  1367. Xstruct tm *tm;
  1368. Xstruct schedcmd *sch,*sch2,*schl;
  1369. Xint t0;
  1370. X
  1371. X    if (s && *s == '-')
  1372. X        {
  1373. X        t0 = atoi(s+1);
  1374. X
  1375. X        if (!t0)
  1376. X            {
  1377. X            zerrnam("sched","usage for delete: sched -<item#>.",NULL,0);
  1378. X            return 1;
  1379. X            }
  1380. X        for (schl = (struct schedcmd *) &schedcmds, sch = schedcmds, t0--;
  1381. X                sch && t0; sch = (schl = sch)->next, t0--);
  1382. X        if (!sch)
  1383. X            {
  1384. X            zerrnam("sched","not that many entries",NULL,0);
  1385. X            return 1;
  1386. X            }
  1387. X        schl->next = sch->next;
  1388. X        free(sch->cmd);
  1389. X        free(sch);
  1390. X        return 0;
  1391. X        }
  1392. X    if (!s)
  1393. X        {
  1394. X        char tbuf[40];
  1395. X
  1396. X        for (t0 = 1, sch = schedcmds; sch; sch = sch->next,t0++)
  1397. X            {
  1398. X            t = sch->time;
  1399. X            tm = localtime(&t);
  1400. X            ztrftime(tbuf,20,"%a %b %e %k:%M:%S",tm);
  1401. X            printf("%3d %s %s\n",t0,tbuf,sch->cmd);
  1402. X            }
  1403. X        return 0;
  1404. X        }
  1405. X    else if (!*argv)
  1406. X        {
  1407. X        zerrnam("sched","not enough arguments",NULL,0);
  1408. X        return 1;
  1409. X        }
  1410. X    if (*s == '+')
  1411. X        {
  1412. X        h = zstrtol(s+1,&s,10);
  1413. X        if (*s != ':')
  1414. X            {
  1415. X            zerrnam("sched","bad time specifier",NULL,0);
  1416. X            return 1;
  1417. X            }
  1418. X        m = zstrtol(s+1,&s,10);
  1419. X        if (*s)
  1420. X            {
  1421. X            zerrnam("sched","bad time specifier",NULL,0);
  1422. X            return 1;
  1423. X            }
  1424. X        t = time(NULL)+h*3600+m*60;
  1425. X        }
  1426. X    else
  1427. X        {
  1428. X        h = zstrtol(s,&s,10);
  1429. X        if (*s != ':')
  1430. X            {
  1431. X            zerrnam("sched","bad time specifier",NULL,0);
  1432. X            return 1;
  1433. X            }
  1434. X        m = zstrtol(s+1,&s,10);
  1435. X        if (*s && *s != 'a' && *s != 'p')
  1436. X            {
  1437. X            zerrnam("sched","bad time specifier",NULL,0);
  1438. X            return 1;
  1439. X            }
  1440. X        t = time(NULL);
  1441. X        tm = localtime(&t);
  1442. X        t -= tm->tm_sec+tm->tm_min*60+tm->tm_hour*3600;
  1443. X        if (*s == 'p')
  1444. X            h += 12;
  1445. X        t += h*3600+m*60;
  1446. X        if (t < time(NULL))
  1447. X            t += 3600*24;
  1448. X        }
  1449. X    sch = zcalloc(sizeof *sch);
  1450. X    sch->time = t;
  1451. X    sch->cmd = ztrdup(spacejoin(argv));
  1452. X    sch->next = NULL;
  1453. X    for (sch2 = (struct schedcmd *) &schedcmds; sch2->next; sch2 = sch2->next);
  1454. X    sch2->next = sch;
  1455. X    return 0;
  1456. X}
  1457. X
  1458. Xint bin_eval(nam,argv,ops,func) /**/
  1459. Xchar *nam;char **argv;char *ops;int func;
  1460. X{
  1461. Xchar *s = ztrdup(spacejoin(argv));
  1462. XList list;
  1463. X
  1464. X    hungets(s);
  1465. X    free(s);
  1466. X    strinbeg();
  1467. X    if (!(list = parse_list()))
  1468. X        {
  1469. X        hflush();
  1470. X        strinend();
  1471. X        return 1;
  1472. X        }
  1473. X    strinend();
  1474. X    runlist(list);
  1475. X    return lastval;
  1476. X}
  1477. X
  1478. X/* get the history event associated with s */
  1479. X
  1480. Xint fcgetcomm(s) /**/
  1481. Xchar *s;
  1482. X{
  1483. Xint cmd;
  1484. X
  1485. X    if (cmd = atoi(s))
  1486. X        {
  1487. X        if (cmd < 0)
  1488. X            cmd = curhist+cmd+1;
  1489. X        return cmd;
  1490. X        }
  1491. X    cmd = hcomsearch(s);
  1492. X    if (cmd == -1)
  1493. X        zerrnam("fc","event not found: %s",s,0);
  1494. X    return cmd;
  1495. X}
  1496. X
  1497. X/* perform old=new substituion */
  1498. X
  1499. Xint fcsubs(sp,sub) /**/
  1500. Xchar **sp;struct asgment *sub;
  1501. X{
  1502. Xchar *s1,*s2,*s3,*s4,*s = *sp,*s5;
  1503. Xint subbed = 0;
  1504. X
  1505. X    while (sub)
  1506. X        {
  1507. X        s1 = sub->name;
  1508. X        s2 = sub->value;
  1509. X        sub = sub->next;
  1510. X        s5 = s;
  1511. X        while (s3 = (char *) ztrstr(s5,s1))
  1512. X            {
  1513. X            s4 = alloc(1+(s3-s)+strlen(s2)+strlen(s3+strlen(s1)));
  1514. X            ztrncpy(s4,s,s3-s);
  1515. X            strcat(s4,s2);
  1516. X            s5 = s4+strlen(s4);
  1517. X            strcat(s4,s3+strlen(s1));
  1518. X            s = s4;
  1519. X            subbed = 1;
  1520. X            }
  1521. X        }
  1522. X    *sp = s;
  1523. X    return subbed;
  1524. X}
  1525. X
  1526. X/* print a series of history events to a file */
  1527. X
  1528. Xint fclist(f,n,r,D,d,first,last,subs) /**/
  1529. XFILE *f;int n;int r;int D;int d;int first;int last;struct asgment *subs;
  1530. X{
  1531. Xint done = 0;
  1532. Xchar *s,*hs;
  1533. XHistent ent;
  1534. X
  1535. X    if (!subs) done = 1;
  1536. X    for (;;) {
  1537. X        hs = quietgetevent(first);
  1538. X        if (!hs) {
  1539. X            zerrnam("fc","no such event: %d",NULL,first);
  1540. X            return 1;
  1541. X        }
  1542. X        s = makehstr(hs);
  1543. X        done |= fcsubs(&s,subs);
  1544. X        if (n) fprintf(f,"%5d  ",first);
  1545. X        ent = NULL;
  1546. X        if (d) {
  1547. X            struct tm *ltm;
  1548. X            
  1549. X            if (!ent) ent = gethistent(first);
  1550. X            ltm = localtime(&ent->stim);
  1551. X            fprintf(f,"%2d:%02d  ",ltm->tm_hour,ltm->tm_min);
  1552. X        }
  1553. X        if (D) {
  1554. X            long diff;
  1555. X
  1556. X            if (!ent) ent = gethistent(first);
  1557. X            diff = (ent->ftim) ? ent->ftim-ent->stim : 0;
  1558. X            fprintf(f,"%d:%02d  ",diff/60,diff%60);
  1559. X        }
  1560. X        if (f == stdout) {
  1561. X            niceprintf(s,f);
  1562. X            putc('\n',f);
  1563. X        } else fprintf(f,"%s\n",s);
  1564. X        if (first == last) break;
  1565. X        (r) ? first-- : first++;
  1566. X    }
  1567. X    if (f != stdout) fclose(f);
  1568. X    if (!done) {
  1569. X        zerrnam("fc","no substitutions performed",NULL,0);
  1570. X        return 1;
  1571. X    }
  1572. X    return 0;
  1573. X}
  1574. X
  1575. Xint fcedit(ename,fn) /**/
  1576. Xchar *ename;char *fn;
  1577. X{
  1578. X    if (!strcmp(ename,"-"))
  1579. X        return 1;
  1580. X    return !zyztem(ename,fn);
  1581. X}
  1582. X
  1583. X/* fc, history, r */
  1584. X
  1585. Xint bin_fc(nam,argv,ops,func) /**/
  1586. Xchar *nam;char **argv;char *ops;int func;
  1587. X{
  1588. Xint first = -1,last = -1,retval,minflag = 0;
  1589. Xchar *s;
  1590. Xstruct asgment *asgf = NULL,*asgl = NULL;
  1591. X
  1592. X    if (!interact) {
  1593. X        zerrnam(nam,"not interactive shell",NULL,0);
  1594. X        return 1;
  1595. X    }
  1596. X    if (!(ops['l'] && unset(HISTNOSTORE))) remhist();
  1597. X    if (ops['R']) {
  1598. X        readhistfile(*argv ? *argv : getsparam("HISTFILE"),1);
  1599. X        return 0;
  1600. X    }
  1601. X    if (ops['W']) {
  1602. X        savehistfile(*argv ? *argv : getsparam("HISTFILE"),1,0);
  1603. X        return 0;
  1604. X    }
  1605. X    if (ops['A']) {
  1606. X        savehistfile(*argv ? *argv : getsparam("HISTFILE"),1,1);
  1607. X        return 0;
  1608. X    }
  1609. X    while (*argv && equalsplit(*argv,&s)) {
  1610. X        struct asgment *a = (struct asgment *) alloc(sizeof *a);
  1611. X
  1612. X        if (!asgf) asgf = asgl = a;
  1613. X        else {
  1614. X            asgl->next = a;
  1615. X            asgl = a;
  1616. X        }
  1617. X        a->name = *argv;
  1618. X        a->value = s;
  1619. X        argv++;
  1620. X    }
  1621. X    if (*argv) {
  1622. X        minflag = **argv == '-';
  1623. X        first = fcgetcomm(*argv);
  1624. X        if (first == -1) return 1;
  1625. X        argv++;
  1626. X    }
  1627. X    if (*argv) {
  1628. X        last = fcgetcomm(*argv);
  1629. X        if (last == -1) return 1;
  1630. X        argv++;
  1631. X    }
  1632. X    if (*argv) {
  1633. X        zerrnam("fc","too many arguments",NULL,0);
  1634. X        return 1;
  1635. X    }
  1636. X    if (first == -1) first = (ops['l']) ? curhist-16 : curhist;
  1637. X    if (last == -1) last = (ops['l']) ? curhist : first;
  1638. X    if (first < firsthist()) first = firsthist();
  1639. X    if (last == -1) last = (minflag) ? curhist : first;
  1640. X    if (ops['l'])
  1641. X        retval = fclist(stdout,!ops['n'],ops['r'],ops['D'],ops['d'],
  1642. X            first,last,asgf);
  1643. X    else {
  1644. X        FILE *out;
  1645. X        char *fil = gettemp();
  1646. X
  1647. X        out = fopen(fil,"w");
  1648. X        if (!out)
  1649. X            zerrnam("fc","can't open temp file: %e",NULL,errno);
  1650. X        else {
  1651. X            retval = 1;
  1652. X            if (!fclist(out,0,ops['r'],0,0,first,last,asgf))
  1653. X                if (fcedit(auxdata ? auxdata : fceditparam,fil))
  1654. X                    if (stuff(fil))
  1655. X                        zerrnam("fc","%e: %s",s,errno);
  1656. X                    else
  1657. X                        retval = 0;
  1658. X        }
  1659. X        unlink(fil);
  1660. X    }
  1661. X    return retval;
  1662. X}
  1663. X
  1664. Xint bin_suspend(name,argv,ops,func) /**/
  1665. Xchar *name;char **argv;char *ops;int func;
  1666. X{
  1667. X    if (islogin && !ops['f']) {
  1668. X        zerrnam(name,"can't suspend login shell",NULL,0);
  1669. X        return 1;
  1670. X    }
  1671. X    if (jobbing) {
  1672. X        signal(SIGPIPE,SIG_DFL);
  1673. X        signal(SIGTTIN,SIG_DFL);
  1674. X        signal(SIGTSTP,SIG_DFL);
  1675. X        signal(SIGTTOU,SIG_DFL);
  1676. X    }
  1677. X    kill(0,SIGTSTP);
  1678. X    if (jobbing) {
  1679. X        while (gettygrp() != mypgrp) {
  1680. X            sleep(1);
  1681. X            if (gettygrp() != mypgrp) kill(0,SIGTTIN);
  1682. X        }
  1683. X        signal(SIGTTOU,SIG_IGN);
  1684. X        signal(SIGTSTP,SIG_IGN);
  1685. X        signal(SIGTTIN,SIG_IGN);
  1686. X        signal(SIGPIPE,SIG_IGN);
  1687. X    }
  1688. X    return 0;
  1689. X}
  1690. X
  1691. Xint bin_alias(name,argv,ops,func) /**/
  1692. Xchar *name;char **argv;char *ops;int func;
  1693. X{
  1694. Xstruct alias *an;
  1695. Xstruct asgment *asg;
  1696. Xint incm = !(ops['a'] || ops['g']),ret = 0;
  1697. X
  1698. X    showflag = !incm;
  1699. X    if (!*argv)
  1700. X        listhtable(aliastab,(HFunc) printalias);
  1701. X    else while (asg = getasg(*argv++))
  1702. X        {
  1703. X        if (asg->value)
  1704. X            addhnode(ztrdup(asg->name),mkanode(ztrdup(asg->value),incm),
  1705. X                aliastab,freeanode);
  1706. X        else if (an = (Alias) gethnode(asg->name,aliastab))
  1707. X            printalias(asg->name,an);
  1708. X        else
  1709. X            ret = 1;
  1710. X        }
  1711. X    return ret;
  1712. X}
  1713. X
  1714. X/* print an alias; used with listhtable */
  1715. X
  1716. Xvoid printalias(s,a) /**/
  1717. Xchar *s;struct alias *a;
  1718. X{
  1719. X    if (a->cmd >= 0 && !(showflag && a->cmd))
  1720. X        printf("%s=%s\n",s,a->text);
  1721. X}
  1722. X
  1723. X/* print a param; used with listhtable */
  1724. X
  1725. Xvoid printparam(s,p) /**/
  1726. Xchar *s;Param p;
  1727. X{
  1728. X    if (showflag > 0 && !(p->flags & showflag))
  1729. X        return;
  1730. X    if (!showflag)
  1731. X        {
  1732. X        int fgs = p->flags;
  1733. X
  1734. X        if (fgs & PMFLAG_i) printf("integer ");
  1735. X        if (fgs & PMFLAG_A) printf("array ");
  1736. X        if (fgs & PMFLAG_L) printf("left justified %d ",p->ct);
  1737. X        if (fgs & PMFLAG_R) printf("right justified %d ",p->ct);
  1738. X        if (fgs & PMFLAG_Z) printf("zero filled %d ",p->ct);
  1739. X        if (fgs & PMFLAG_l) printf("lowercase ");
  1740. X        if (fgs & PMFLAG_u) printf("uppercase ");
  1741. X        if (fgs & PMFLAG_r) printf("readonly ");
  1742. X        if (fgs & PMFLAG_t) printf("tagged ");
  1743. X        if (fgs & PMFLAG_x) printf("exported ");
  1744. X        }
  1745. X    if (showflag2)
  1746. X        printf("%s\n",s);
  1747. X    else
  1748. X        {
  1749. X        char *t,**u;
  1750. X
  1751. X        printf("%s=",s);
  1752. X        switch (p->flags & PMTYPE)
  1753. X            {
  1754. X            case PMFLAG_s:
  1755. X                if (p->gets.cfn && (t = p->gets.cfn(p)))
  1756. X                    puts(t);
  1757. X                else
  1758. X                    putchar('\n');
  1759. X                break;
  1760. X            case PMFLAG_i: printf("%ld\n",p->gets.ifn(p)); break;
  1761. X            case PMFLAG_A:
  1762. X                putchar('(');
  1763. X                u = p->gets.afn(p);
  1764. X                if (!*u)
  1765. X                    printf(")\n");
  1766. X                else
  1767. X                    {
  1768. X                    while (u[1])
  1769. X                        printf("%s ",*u++);
  1770. X                    printf("%s)\n",*u);
  1771. X                    }
  1772. X                break;
  1773. X            }
  1774. X        }
  1775. X}
  1776. X
  1777. X/* autoload, declare, export, functions, integer, local, readonly, typeset */
  1778. X
  1779. Xint bin_typeset(name,argv,ops,func) /**/
  1780. Xchar *name;char **argv;char *ops;int func;
  1781. X{
  1782. Xint on = 0,off = 0,roff,bit = 1,retcode = 0;
  1783. Xchar *optstr = "LRZilurtx";
  1784. Xstruct param *pm;
  1785. Xstruct asgment *asg;
  1786. X
  1787. X    for (; *optstr; optstr++,bit <<= 1)
  1788. X        if (ops[*optstr] == 1)
  1789. X            on |= bit;
  1790. X        else if (ops[*optstr] == 2)
  1791. X            off |= bit;
  1792. X    roff = off;
  1793. X    if (ops['f']) {
  1794. X        on &= PMFLAG_t|PMFLAG_u;
  1795. X        off &= PMFLAG_t|PMFLAG_u;
  1796. X        showflag = (ops['f'] == 1);
  1797. X        if (ops['@'] && ((off & ~PMFLAG_t) || (on & ~(PMFLAG_u|PMFLAG_t)))) {
  1798. X            zerrnam(name,"invalid option(s)",NULL,0);
  1799. X            return 1;
  1800. X        }
  1801. X        showflag2 = 0;
  1802. X        if (!*argv) {
  1803. X            showflag2 = off|on;
  1804. X            listhtable(cmdnamtab,(HFunc) pshfunc);
  1805. X        } else for (; *argv; argv++) {
  1806. X            Cmdnam cc;
  1807. X
  1808. X            if ((cc = (Cmdnam) gethnode(*argv,cmdnamtab)) && cc->type == SHFUNC)
  1809. X                if (on|off) cc->flags = (cc->flags | on) & (~off);
  1810. X                else pshfunc(*argv,cc);
  1811. X            else if (on & PMFLAG_u) {
  1812. X                cc = (Cmdnam) zcalloc(sizeof *cc);
  1813. X                cc->type = SHFUNC;
  1814. X                cc->flags = on;
  1815. X                addhnode(ztrdup(*argv),cc,cmdnamtab,freecmdnam);
  1816. X            } else
  1817. X                retcode = 1;
  1818. X        }
  1819. X        return retcode;
  1820. X    }
  1821. X    if (on & PMFLAG_L)
  1822. X        off |= PMFLAG_R;
  1823. X    if (on & PMFLAG_R)
  1824. X        off |= PMFLAG_L;
  1825. X    if (on & PMFLAG_u)
  1826. X        off |= PMFLAG_l;
  1827. X    if (on & PMFLAG_l)
  1828. X        off |= PMFLAG_u;
  1829. X    on &= ~off;
  1830. X    showflag = showflag2 = 0;
  1831. X    if (!*argv) {
  1832. X        showflag = on|off;
  1833. X        showflag2 = roff;
  1834. X        listhtable(paramtab,(HFunc) printparam);
  1835. X    } else while (asg = getasg(*argv++)) {
  1836. X        if (asg->value && *asg->value == '~') {
  1837. X            *asg->value = Tilde;
  1838. X            singsub(&asg->value);
  1839. X        }
  1840. X        pm = (Param) gethnode(asg->name,paramtab);
  1841. X        if (pm) {
  1842. X            if (!on && !roff && !asg->value) {
  1843. X                printparam(asg->name,pm);
  1844. X                continue;
  1845. X            }
  1846. X            pm->flags = (pm->flags | on) & ~off;
  1847. X            if ((on & (PMFLAG_L | PMFLAG_R | PMFLAG_Z | PMFLAG_i)) 
  1848. X                    && (pmtype(pm) != PMFLAG_A))
  1849. X                pm->ct = auxlen;
  1850. X            if (pmtype(pm) != PMFLAG_A) {
  1851. X                if (pm->flags & PMFLAG_x) {
  1852. X                    if (!pm->env)
  1853. X                        pm->env = addenv(asg->name,
  1854. X                            (asg->value) ? asg->value : getsparam(asg->name));
  1855. X                } else if (pm->env) {
  1856. X                    delenv(pm->env);
  1857. X                    free(pm->env);
  1858. X                    pm->env = NULL;
  1859. X                }
  1860. X                if (asg->value)
  1861. X                    setsparam(asg->name,ztrdup(asg->value));
  1862. X            }
  1863. X        } else {
  1864. X            if (locallist && !(on & PMFLAG_x)) {
  1865. X                permalloc();
  1866. X                addnode(locallist,ztrdup(asg->name));
  1867. X                heapalloc();
  1868. X            }
  1869. X            createparam(ztrdup(asg->name),
  1870. X                ztrdup((asg->value) ? asg->value : ""),on);
  1871. X            pm = (Param) gethnode(asg->name,paramtab);
  1872. X            pm->ct = auxlen;
  1873. X        }
  1874. X    }
  1875. X    return 0;
  1876. X}
  1877. X
  1878. X/* convert s with escape sequences */
  1879. X
  1880. Xchar *escsubst(s,nnl) /**/
  1881. Xchar *s; int *nnl;
  1882. X{
  1883. Xchar *t = alloc(strlen(s)+1),*ret = t;
  1884. X
  1885. X    for (; *s; s++)
  1886. X        if (*s == '\\' && s[1])
  1887. X            switch (*++s) {
  1888. X                case 'b': *t++ = '\b'; break;
  1889. X                case 'c': *nnl |= 1; break;
  1890. X                case 'e': *t++ = '\033'; break;
  1891. X                case 'f': *t++ = '\f'; break;
  1892. X                case 'n': *t++ = '\n'; break;
  1893. X                case 'r': *t++ = '\r'; break;
  1894. X                case 't': *t++ = '\t'; break;
  1895. X                case 'v': *t++ = '\v'; break;
  1896. X                case '\\': *t++ = '\\'; break;
  1897. X                case '0': *t++ = zstrtol(s,&s,8); s--; break;
  1898. X                default: *t++ = '\\'; *t++ = *s; break;
  1899. X            }
  1900. X        else *t++ = *s;
  1901. X    *t = '\0';
  1902. X    return ret;
  1903. X}
  1904. X
  1905. X/* echo, print, pushln */
  1906. X
  1907. Xint bin_print(name,args,ops,func) /**/
  1908. Xchar *name;char **args;char *ops;int func;
  1909. X{
  1910. Xint nnl = 0, fd;
  1911. XHistent ent;
  1912. XFILE *fout = stdout;
  1913. X
  1914. X    if (ops['z']) {
  1915. X        permalloc();
  1916. X        pushnode(bufstack,ztrdup(spacejoin(args)));
  1917. X        heapalloc();
  1918. X        return 0;
  1919. X    }
  1920. X    if (ops['s']) {
  1921. X        permalloc();
  1922. X        ent = gethistent(++curhist);
  1923. X        ent->lex = ztrdup(join(args,HISTSPACE));
  1924. X        ent->lit = ztrdup(join(args,' '));
  1925. X        ent->stim = ent->ftim = time(NULL);
  1926. X        heapalloc();
  1927. X        return 0;
  1928. X    }
  1929. X    if (ops['R'])
  1930. X        ops['r'] = 1;
  1931. X    if (ops['u'] || ops['p']) {
  1932. X        if (ops['u']) {
  1933. X            for (fd = 0; fd < 10; fd++) if (ops[fd+'0']) break;
  1934. X            if (fd == 10) fd = 0;
  1935. X        } else fd = coprocout;
  1936. X        if ((fd = dup(fd)) < 0) {
  1937. X            zerrnam(name,"bad file number",NULL,0);
  1938. X            return 1;
  1939. X        }
  1940. X        if ((fout = fdopen(fd,"w")) == 0) {
  1941. X            zerrnam(name,"bad mode on fd",NULL,0);
  1942. X            return 1;
  1943. X        }
  1944. X    }
  1945. X    for (; *args; args++) {
  1946. X        if (!ops['r']) *args = escsubst(*args,&nnl);
  1947. X        if (ops['D']) fprintdir(*args,fout);
  1948. X        else if (ops['P']) {
  1949. X            int junk;
  1950. X            fputs(putprompt(*args,&junk),fout);
  1951. X        } else fputs(*args,fout);
  1952. X        if (args[1]) fputc(ops['l'] ? '\n' : ops['0'] ? '\0' : ' ',fout);
  1953. X    }
  1954. X    if (!(ops['n'] || nnl)) fputc(ops['N'] ? '\0' : '\n',fout);
  1955. X    if (fout != stdout) fclose(fout);
  1956. X    return 0;
  1957. X}
  1958. X
  1959. Xint bin_dirs(name,argv,ops,func) /**/
  1960. Xchar *name;char **argv;char *ops;int func;
  1961. X{
  1962. XLklist l;
  1963. X
  1964. X    if (ops['v'])
  1965. X        {
  1966. X        Lknode node;
  1967. X        int t0 = 1;
  1968. X
  1969. X        printf("0\t");
  1970. X        printdir(pwd);
  1971. X        for (node = firstnode(dirstack); node; incnode(node))
  1972. X            {
  1973. X            printf("\n%d\t",t0++);
  1974. X            printdir(getdata(node));
  1975. X            }
  1976. X        putchar('\n');
  1977. X        return 0;
  1978. X        }
  1979. X    if (!*argv)
  1980. X        {
  1981. X        pdstack();
  1982. X        return 0;
  1983. X        }
  1984. X    permalloc();
  1985. X    l = newlist();
  1986. X    if (!*argv)
  1987. X        {
  1988. X        heapalloc();
  1989. X        return 0;
  1990. X        }
  1991. X    while (*argv)
  1992. X        addnode(l,ztrdup(*argv++));
  1993. X    freetable(dirstack,freestr);
  1994. X    dirstack = l;
  1995. X    heapalloc();
  1996. X    return 0;
  1997. X}
  1998. X
  1999. Xint bin_unalias(name,argv,ops,func) /**/
  2000. Xchar *name;char **argv;char *ops;int func;
  2001. X{
  2002. Xint ret = 0;
  2003. Xvptr dat;
  2004. X
  2005. X    while (*argv)
  2006. X        {
  2007. X        if (dat = remhnode(*argv++,aliastab))
  2008. X            freeanode(dat);
  2009. X        else
  2010. X            ret = 1;
  2011. X        }
  2012. X    return ret;
  2013. X}
  2014. X
  2015. Xint bin_disable(name,argv,ops,func) /**/
  2016. Xchar *name;char **argv;char *ops;int func;
  2017. X{
  2018. XCmdnam chn;
  2019. X
  2020. X    while (*argv) {
  2021. X        if (!strncmp(*argv,"TRAP",4))
  2022. X            unsettrap(getsignum(*argv+4));
  2023. X        chn = zalloc(sizeof *chn);
  2024. X        chn->type = DISABLED;
  2025. X        addhnode(ztrdup(*argv++),chn,cmdnamtab,freecmdnam);
  2026. X    }
  2027. X    return 0;
  2028. X}
  2029. X
  2030. Xint bin_unhash(name,argv,ops,func) /**/
  2031. Xchar *name;char **argv;char *ops;int func;
  2032. X{
  2033. Xvptr dat;
  2034. X
  2035. X    while (*argv) {
  2036. X        if (!strncmp(*argv,"TRAP",4)) unsettrap(getsignum(*argv+4));
  2037. X        if (dat = remhnode(*argv++,cmdnamtab)) freecmdnam(dat);
  2038. X    }
  2039. X    return 0;
  2040. X}
  2041. X
  2042. Xint bin_unset(name,argv,ops,func) /**/
  2043. Xchar *name;char **argv;char *ops;int func;
  2044. X{
  2045. Xint retval = 0;
  2046. Xchar *s;
  2047. X
  2048. X    while (s = *argv++)
  2049. X        if (gethnode(s,paramtab))
  2050. X            unsetparam(s);
  2051. X        else
  2052. X            retval = 1;
  2053. X    return retval;
  2054. X}
  2055. X
  2056. Xstatic char *zbuf;
  2057. Xstatic int readfd;
  2058. X
  2059. Xint zread() /**/
  2060. X{
  2061. Xchar cc;
  2062. X
  2063. X    if (zbuf)
  2064. X        return (*zbuf) ? *zbuf++ : EOF;
  2065. X    if (read(readfd,&cc,1) != 1)
  2066. X        return EOF;
  2067. X    return cc;
  2068. X}
  2069. X
  2070. Xint bin_read(name,args,ops,func) /**/
  2071. Xchar *name;char **args;char *ops;int func;
  2072. X{
  2073. Xchar *reply,*pmpt;
  2074. Xint bsiz,c,gotnl = 0;
  2075. Xchar *buf,*bptr;
  2076. X
  2077. X    reply = (*args) ? *args++ : "REPLY";
  2078. X    if (ops['u'] && !ops['p']) {
  2079. X        for (readfd = 0; readfd < 10; ++readfd) if (ops[readfd+'0']) break;
  2080. X        if (readfd == 10) readfd = 0;
  2081. X    } else if (ops['p']) readfd = coprocin;
  2082. X    else {
  2083. X        attachtty((jobtab[thisjob].gleader) ? jobtab[thisjob].gleader : mypgrp);
  2084. X        readfd = 0;
  2085. X        if (isatty(0)) {
  2086. X            for (pmpt = reply; *pmpt && *pmpt != '?'; pmpt++);
  2087. X            if (*pmpt++) {
  2088. X                write(2,pmpt,strlen(pmpt));
  2089. X                pmpt[-1] = '\0';
  2090. X            }
  2091. X        }
  2092. X#if 0
  2093. X        else if (isset(SHINSTDIN) && unset(INTERACTIVE)) {
  2094. X            if (isatty(1)) readfd = 1;
  2095. X            else if (isatty(2)) readfd = 2;
  2096. X        }
  2097. X#endif
  2098. X    }
  2099. X    zbuf = (!ops['z']) ? NULL :
  2100. X        (full(bufstack)) ? (char *) getnode(bufstack) : NULL;
  2101. X    while (*args) {
  2102. X        buf = bptr = zalloc(bsiz = 64);
  2103. Xredo:
  2104. X        for(;;) {
  2105. X            if (gotnl) break;
  2106. X            c = zread();
  2107. X            if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\') {
  2108. X                bptr--;
  2109. X                continue;
  2110. X            }
  2111. X            if (c == EOF || isep(c) || c == '\n') break;
  2112. X            *bptr++ = c;
  2113. X            if (bptr == buf+bsiz) {
  2114. X                buf = realloc(buf,bsiz *= 2);
  2115. X                bptr = buf+(bsiz/2);
  2116. X            }
  2117. X        }
  2118. X        if (c == EOF) {
  2119. X            if (readfd == coprocin) {
  2120. X                close(coprocin);
  2121. X                close(coprocout);
  2122. X                coprocin = coprocout = -1;
  2123. X            }
  2124. X            return 1;
  2125. X        }
  2126. X        if (c == '\n') gotnl = 1;
  2127. X        if (bptr == buf) goto redo;
  2128. X        *bptr = '\0';
  2129. X        setsparam(reply,buf);
  2130. X        reply = *args++;
  2131. X    }
  2132. X    buf = bptr = zalloc(bsiz = 64);
  2133. X    if (!gotnl)
  2134. X        for (;;) {
  2135. X            c = zread();
  2136. X            if (!ops['r'] && c == '\n' && bptr != buf && bptr[-1] == '\\') {
  2137. X                bptr--;
  2138. X                continue;
  2139. X            }
  2140. X            if (c == EOF || (c == '\n' && !zbuf)) break;
  2141. X            *bptr++ = c;
  2142. X            if (bptr == buf+bsiz) {
  2143. X                buf = realloc(buf,bsiz *= 2);
  2144. X                bptr = buf+(bsiz/2);
  2145. X            }
  2146. X        }
  2147. X    *bptr = '\0';
  2148. X    setsparam(reply,buf);
  2149. X    if (c == EOF) {
  2150. X        if (readfd == coprocin) {
  2151. X            close(coprocin);
  2152. X            close(coprocout);
  2153. X            coprocin = coprocout = -1;
  2154. X        }
  2155. X        return 1;
  2156. X    }
  2157. X    return 0;
  2158. X}
  2159. X
  2160. Xint bin_vared(name,args,ops,func) /**/
  2161. Xchar *name;char **args;char *ops;int func;
  2162. X{
  2163. Xchar *s;char *t;
  2164. Xstruct param *pm;
  2165. X
  2166. X    if (!(s = getsparam(args[0]))) {
  2167. X        zerrnam(name,"no such variable: %s",args[0],0);
  2168. X        return 1;
  2169. X    }
  2170. X    permalloc();
  2171. X    pushnode(bufstack,ztrdup(s));
  2172. X    heapalloc();
  2173. X    t = (char *) zleread((unsigned char *)"> ",NULL,2);
  2174. X    if (!t || errflag)
  2175. X        return 1;
  2176. X    if (t[strlen(t)-1] == '\n')
  2177. X        t[strlen(t)-1] = '\0';
  2178. X    pm = gethnode(args[0],paramtab);
  2179. X    if (pmtype(pm) == PMFLAG_A)
  2180. X        setaparam(args[0],spacesplit(t));
  2181. X    else
  2182. X        setsparam(args[0],t);
  2183. X    return 0;
  2184. X}
  2185. X
  2186. X#define fset(X) (flags & X)
  2187. X
  2188. X/* execute a builtin handler function after parsing the arguments */
  2189. X
  2190. Xint execbin(args,cnode) /**/
  2191. XLklist args;Cmdnam cnode;
  2192. X{
  2193. Xstruct bincmd *b;
  2194. Xchar ops[128],*arg,*pp,*name,**argv,**oargv,*optstr;
  2195. Xint t0,flags,sense,argc = 0,op;
  2196. XLknode n;
  2197. X
  2198. X    auxdata = NULL;
  2199. X    auxlen = 0;
  2200. X    for (t0 = 0; t0 != 128; t0++)
  2201. X        ops[t0] = 0;
  2202. X    name = ugetnode(args);
  2203. X    b = builtins+cnode->u.binnum;
  2204. X
  2205. X/* the 'builtin' builtin is handled specially */
  2206. X
  2207. X    if (b->funcid == BIN_BUILTIN)
  2208. X        {
  2209. X        if (!(name = ugetnode(args)))
  2210. X            {
  2211. X            zerrnam("builtin","command name expected",NULL,0);
  2212. X            return 1;
  2213. X            }
  2214. X        for (t0 = 0, b = builtins; b->name; b++,t0++)
  2215. X            if (!strcmp(name,b->name))
  2216. X                break;
  2217. X        if (!b->name)
  2218. X            {
  2219. X            zerrnam("builtin","no such builtin: %s",name,0);
  2220. X            return 1;
  2221. X            }
  2222. X        }
  2223. X    flags = b->flags;
  2224. X    arg = ugetnode(args);
  2225. X    optstr = b->optstr;
  2226. SHAR_EOF
  2227. true || echo 'restore of zsh2.2/src/builtin.c failed'
  2228. fi
  2229. echo 'End of zsh2.2 part 6'
  2230. echo 'File zsh2.2/src/builtin.c is continued in part 7'
  2231. echo 7 > _shar_seq_.tmp
  2232. exit 0
  2233.  
  2234. exit 0 # Just in case...
  2235.